<template>
    <div ref="BoxRef">
        <audio ref="audioRef"></audio>
    </div>
</template>

<script setup lang="ts">
import Player,  { EVENT } from 'nplayer'
import {ref } from 'vue'
import { getWbiKeys,encWbi } from '@/api/getVideo'
import { get } from '@/http/axios'
import { createFFmpeg, fetchFile } from '@ffmpeg/ffmpeg'
import { Timer } from '@element-plus/icons-vue/dist/types'

interface Props{
    avid:number,
    bvid:string,
    cid:number
}

const props = defineProps<Props>()
const BoxRef = ref()
const audioRef = ref()
let allVideoUrl = ref()
let allAudioUrl = ref()
let player:any = null
let timer:Timer | null = null
let video:any = null
let errIndex: number = 0
let audioErrIndex:number = 0

getVideo()
video = document.createElement('video')

/**
 * 
 * @param qn 画质
 * @param type 类型 未传入默认初次加载 audio 音频 video 视频
 * 我尝试过降低画质 但是没有作用
 */
function getVideo(){
    const wbi_keys = getWbiKeys()
    const query = encWbi(
    {
        qn:'80',
        fnver:'0',
        fnval:'4048',
        fourk:'1',
        gaia_source:'pre-load',
        voice_balance: '1',
        avid:props.avid,
        bvid:props.bvid,
        cid:props.cid,
    },
    wbi_keys.img_key, 
    wbi_keys.sub_key
    )
    get('/x/player/wbi/playurl?' + query,'','/bili').then(res => {
        console.log('视频初始加载数据',res);
        allVideoUrl.value = res.data.dash.video
        allAudioUrl.value = res.data.dash.audio
        return  tranMp3(res.data.dash.audio[0].base_url)
    })
}
//音频转码
async function tranMp3(audiourl:string):Promise<any>{    
    const ffmpeg = createFFmpeg({ 
        mainName: 'main',
        corePath: 'https://unpkg.com/@ffmpeg/core-st@0.11.1/dist/ffmpeg-core.js',
    })
    await ffmpeg.load()
    try{
        await ffmpeg.FS('writeFile', "input.m4s", await fetchFile(audiourl))
        await ffmpeg.run('-i', 'input.m4s',"-c:a","copy",'test.aac')
        const data = ffmpeg.FS('readFile', 'test.aac')
        audioRef.value.src = URL.createObjectURL(new Blob([data.buffer], { type: 'audio/aac' }))
        return createVideo()
    } catch(err) {
        audioErrIndex++
        if (audioErrIndex >= allAudioUrl.value.length && audioErrIndex < allAudioUrl.value.length * 2 ) {        
            return  tranMp3(allAudioUrl.value[audioErrIndex - allAudioUrl.value.length].baseUrl) 
        } else if (audioErrIndex === allAudioUrl.value.length * 2 ) {
            alert('全部音频媒体流都存在问题噢 无法加载数据')
           return
        } else {
            return tranMp3(allAudioUrl.value[audioErrIndex].base_url)
        }
    }
}
function createVideo() : void{
    video.src = allVideoUrl.value[0].base_url
    video.addEventListener('error',deteUrl)
    video.addEventListener('loadedmetadata',successLoad)
    player = new Player({ video, autoplay: true, volumeVertical:true })
}

//10s校准一次 视频进度校准音频进度
//由于已经可以播放了 这里面清除video的error监听器
function createTimer(){
    if (timer) clearInterval(timer)
    timer = setInterval(() => {
        console.log('校准一次');
        video.removeEventListener('error',deteUrl)
        audioRef.value.currentTime = player.currentTime
    },10000)
}
//地址存在问题时触发  暴力算法递推查找
function deteUrl() {
    console.log('视频加载失败');
    errIndex ++
    if (errIndex >= allVideoUrl.value.length && errIndex < allVideoUrl.value.length * 2 ) {        
        video.src = allVideoUrl.value[errIndex - allVideoUrl.value.length].baseUrl
        return 
    }
    if (errIndex === allVideoUrl.value.length * 2 ) {
        video.removeEventListener('error',deteUrl)
        alert('全部视频媒体源都存在问题噢 无法加载数据 将降低画质')
        return
    }
    video.src = allVideoUrl.value[errIndex].base_url
    return
}
//地址正确时 开启player监听器 为什么不关闭 video.removeEventListener
//因为有些地址隐性正确 但却不能访问到数据 会让监听器误认为正确
function successLoad() {
    console.log('视频加载成功');
    //video.removeEventListener('error',deteUrl)
    //停止播放
    player.on(EVENT.PAUSE,() => {
        if (document.visibilityState === 'hidden'){
            player.play()
        }
        //停止播放时 停止校准
        clearInterval(timer)
        audioRef.value.pause()
    })
    //开始播放
    player.on(EVENT.PLAY, () => {
        //重新开启播放时 开启校准
        createTimer()
        audioRef.value.currentTime = player.currentTime
        audioRef.value.play()
    })
    //变速
    player.on(EVENT.RATE_CHANGE,() => {
        audioRef.value.playbackRate = player.playbackRate
    })
    //直接拉进度
    player.on(EVENT.SEEKED, () => {
        audioRef.value.currentTime = player.currentTime
    })
    //设置音量
    player.on(EVENT.VOLUME_CHANGE, () => {
        audioRef.value.volume = player.volume
    })
    //在加载时
    player.on(EVENT.LOADING_SHOW,() => {
        audioRef.value.pause()
    })
    //加载结束时
    player.on(EVENT.LOADING_HIDE,() => {
        //console.log('加载结束');
        player.play()
        audioRef.value.play()
    })
    player.mount(BoxRef.value)
}
</script>

<style lang="scss" scoped>
</style>